﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace Cinser.DataTranslate
{
    public delegate Cinser.Common.Model.Message ExceptionDelegate(DataRow dr, Exception ex);
    public delegate Cinser.Common.Model.Message DataRowDelegate(DataRow dr);
    public delegate Cinser.Common.Model.Message DataTableDelegate(DataTable dt);
    public delegate void SendMessageDelegate(Cinser.Common.Model.Message msg);

    public class DBTransplantation
    {
        private static object _SyncRoot = new object();
        public SendMessageDelegate SendMessage;
        public Dictionary<string, TranslateTableSettings> TableSettingsMapping = new Dictionary<string, TranslateTableSettings>();

        TranslateDalBase sourceDal;
        TranslateDalBase targetDal;

        public DBTransplantation(TranslateDalBase sourceDal, TranslateDalBase targetDal)
        {
            this.sourceDal = sourceDal;
            this.targetDal = targetDal;
        }

        /// <summary>
        /// 迁移全部表格数据
        /// </summary>
        public void TranslateAllTables(TaskManager.TaskBase taskInstance)
        {
            List<string> tableNames = sourceDal.GetAllTableNames();
            foreach (var item in tableNames)
            {
                if (targetDal.IsExistTable(item))
                {
                    Translate(new TranslateTableSettings(item, taskInstance));
                }
                else
                {
                    SendMsg(new Cinser.Common.Model.Message("目标数据库不存在表" + item, Cinser.Common.Model.Message.MessageType.Warning));
                }

            }
        }

        /// <summary>
        /// 转移单表数据
        /// </summary>
        /// <param name="tableSettings">数据迁移配置类</param>
        /// <param name="sqlWhere">where条件</param>
        public void Translate(TranslateTableSettings tableSettings, string sqlWhere = "1=1")
        {
            try
            {
                int failedTaskCount = 0;
                if (sourceDal.IsExistTable(tableSettings.SourceTbName) && targetDal.IsExistTable(tableSettings.TargetTbName))
                {
                    //从源数据表中获取要转移的数据
                    DataTable dt = sourceDal.GetDataList(tableSettings.SourceTbName, sqlWhere);
                    if (dt != null && dt.Rows.Count > 0)
                    {
                        tableSettings.TaskInstance.AddTaskMsg(new Cinser.Common.Model.Message(string.Format("开始转移{0}表，数据共：{1}条。",
                            tableSettings.SourceTbName, dt.Rows.Count), Cinser.Common.Model.Message.MessageType.Info));
                        tableSettings.TaskInstance.SubTaskCount = dt.Rows.Count;
                        tableSettings.TaskInstance.FinishedSubTaskCount = 0;
                    }

                    bool bContinue = true;

                    //执行转移前委托方法
                    if (tableSettings.BeforeAddOrUpdate != null)
                    {
                        SendMsg(tableSettings.BeforeAddOrUpdate(dt), out bContinue);
                    }

                    if (bContinue && dt != null && dt.Rows.Count > 0)
                    {
                        //匹配columnMapping
                        if (tableSettings.ColumnsMapping.Count > 0)
                        {
                            foreach (var item in tableSettings.ColumnsMapping)
                            {
                                dt.Columns[item.Key].ColumnName = item.Value;
                            }
                        }

                        //过滤目标表中不存在的字段
                        List<string> targetColumns = targetDal.GetColumns(tableSettings.TargetTbName);
                        for (int i = 0; i < dt.Columns.Count; i++)
                        {
                            if (targetColumns.Contains(dt.Columns[i].ColumnName) == false)
                            {
                                dt.Columns.Remove(dt.Columns[i]);
                                i--;
                            }
                        }

                        foreach (DataRow dr in dt.Rows)
                        {
                            lock (_SyncRoot)
                            {

                                //执行转移中委托方法
                                bContinue = true;
                                if (tableSettings.AddOrUpdating != null)
                                {
                                    SendMsg(tableSettings.AddOrUpdating(dr), out bContinue);
                                }

                                //将数据添加至目标数据库中
                                if (bContinue)
                                {
                                    try
                                    {
                                        if (tableSettings.KeysColumns.Count > 0)
                                            targetDal.Add(tableSettings.TargetTbName, dr, tableSettings.KeysColumns.ToArray());
                                        else
                                            targetDal.Add(tableSettings.TargetTbName, dr);

                                        //执行添加后委托方法
                                        if (tableSettings.AddOrUpdated != null)
                                        {
                                            SendMsg(tableSettings.AddOrUpdated(dr, null));
                                        }
                                    }
                                    catch (Exception ex2)
                                    {
                                        //执行添加后委托方法
                                        if (tableSettings.AddOrUpdated != null)
                                        {
                                            SendMsg(tableSettings.AddOrUpdated(dr, ex2));
                                        }
                                        string dataStr = GetDataDescriptionStr(dr, tableSettings.KeysColumns);
                                        Cinser.Common.Model.Message msg = new Cinser.Common.Model.Message(string.Format("源数据表“{0}”中数据“{1}”转移失败，失败原因：{2}。", tableSettings.SourceTbName
                                                , dataStr, ex2.Message), Cinser.Common.Model.Message.MessageType.Error);
                                        SendMsg(msg);
                                        tableSettings.TaskInstance.WriteDbLog(msg.MsgContent, tableSettings.SourceTbName,
                                            Common.DataTableExtension.GetSqlWhere(dr, tableSettings.KeysColumns));
                                        failedTaskCount++;
                                        tableSettings.TaskInstance.ErrorNum++;
                                    }
                                    tableSettings.TaskInstance.FinishedSubTaskCount++;
                                    tableSettings.TaskInstance.TotalTaskCount++;
                                }
                            }
                        }
                    }
                    if (dt != null && dt.Rows.Count > 0)
                        SendMsg(new Cinser.Common.Model.Message(tableSettings.SourceTbName + "表数据转移完毕。成功："
                            + (dt.Rows.Count - failedTaskCount) + "条，失败：" + failedTaskCount + "条。",
                            failedTaskCount == 0 ? Cinser.Common.Model.Message.MessageType.Info :
                            Cinser.Common.Model.Message.MessageType.Warning));
                }
                else
                {
                    string msgContent = string.Format("源数据表:{0}，或者目标数据表{1}不存在。请修正后重导该表数据。"
                        , tableSettings.SourceTbName, tableSettings.TargetTbName);
                    SendMsg(new Cinser.Common.Model.Message(msgContent, Cinser.Common.Model.Message.MessageType.Error));
                    tableSettings.TaskInstance.WriteDbLog(msgContent, tableSettings.SourceTbName);
                    tableSettings.TaskInstance.TotalTaskCount++;
                    tableSettings.TaskInstance.ErrorNum++;
                }
            }
            catch (Exception ex)
            {
                string msgContent = string.Format("在移植{0}表数据时发生异常：{1}", tableSettings.SourceTbName, ex.Message);
                SendMsg(new Cinser.Common.Model.Message(msgContent, Cinser.Common.Model.Message.MessageType.Exception, ex));
                tableSettings.TaskInstance.WriteDbLog(msgContent, tableSettings.SourceTbName);
                tableSettings.TaskInstance.TotalTaskCount++;
                tableSettings.TaskInstance.ErrorNum++;
            }
        }

        public string GetDataDescriptionStr(DataRow dr, List<string> KeysColumns)
        {
            return Common.DataTableExtension.GetSqlWhere(dr, KeysColumns);
        }

        /// <summary>
        /// 向外界发送一条消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void SendMsg(Cinser.Common.Model.Message msg)
        {
            if (msg != null && string.IsNullOrEmpty(msg.MsgContent) == false)
            {
                if (SendMessage != null)
                    SendMessage(msg);

            }
        }

        private void SendMsg(Cinser.Common.Model.Message msg, out bool bContiniu)
        {
            bContiniu = true;
            if (msg != null && string.IsNullOrEmpty(msg.MsgContent) == false)
            {
                if (SendMessage != null)
                    SendMessage(msg);
                if (msg.Type == Cinser.Common.Model.Message.MessageType.Warning || msg.Type == Cinser.Common.Model.Message.MessageType.Error || msg.Type == Cinser.Common.Model.Message.MessageType.Exception)
                {
                    bContiniu = false;
                }
            }
        }
    }

}
